package com.nuoniu.sibanyun.service.so.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.BaseEntity;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.lang.StringUtils;
import com.nuoniu.sibanyun.entity.bo.VoucherDetailBo;
import com.nuoniu.sibanyun.entity.bo.VoucherMainBo;
import com.nuoniu.sibanyun.entity.bo.VoucherSearchBo;
import com.nuoniu.sibanyun.entity.crm.CrmCustomer;
import com.nuoniu.sibanyun.entity.erp.ErpNumberSet;
import com.nuoniu.sibanyun.entity.erp.ErpProject;
import com.nuoniu.sibanyun.entity.po.VPoPurchaseOrderMain;
import com.nuoniu.sibanyun.entity.production.ErpMrpRecord;
import com.nuoniu.sibanyun.entity.production.VProductionPlanMain;
import com.nuoniu.sibanyun.entity.so.VSaleOrderDetail;
import com.nuoniu.sibanyun.entity.so.VSaleOrderMain;
import com.nuoniu.sibanyun.entity.so.VSaleQuotationDetail;
import com.nuoniu.sibanyun.entity.so.VSaleQuotationMain;
import com.nuoniu.sibanyun.mapper.erp.ErpNumberSetMapper;
import com.nuoniu.sibanyun.mapper.so.VSaleOrderMainMapper;
import com.nuoniu.sibanyun.service.crm.ICrmCustomerService;
import com.nuoniu.sibanyun.service.crm.ICrmGoodsService;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpNumberSetService;
import com.nuoniu.sibanyun.service.erp.IErpProjectService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherDesignService;
import com.nuoniu.sibanyun.service.production.IVProductionPlanDetailService;
import com.nuoniu.sibanyun.service.production.IVProductionPlanMainService;
import com.nuoniu.sibanyun.service.so.IVSaleOrderDetailService;
import com.nuoniu.sibanyun.service.so.IVSaleOrderMainService;
import com.nuoniu.sibanyun.service.utils.ErpUtils;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.apache.xmlbeans.impl.xb.xmlconfig.Usertypeconfig;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 销售订单主表 服务实现类
 * </p>
 *
 * @author baiqiang
 * @since 2020-11-26
 */
@Service
public class VSaleOrderMainServiceImpl extends ServiceImpl<VSaleOrderMainMapper, VSaleOrderMain> implements IVSaleOrderMainService {

    @Autowired
    private IErpNumberSetService numberSetService;
    @Autowired
    private IErpAccountService accountService;
    @Autowired
    private IVSaleOrderDetailService orderDetailService;
    @Autowired
    private IErpAccountService erpAccountService;
    @Autowired
    private ErpNumberSetMapper numberSetMapper;
    @Autowired
    private IErpVoucherDesignService erpVoucherDesignService;
    @Autowired
    private IVProductionPlanDetailService productionPlanDetailService;
    @Autowired
    private IVProductionPlanMainService productionPlanMainService;
    @Autowired
    private ICrmCustomerService crmCustomerService;
    @Autowired
    private ICrmGoodsService crmGoodsService;
    @Autowired
    private IErpProjectService projectService;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void saveOrder(VSaleOrderMain saleOrderMain) {
        Boolean isNewMain = false;
        Long mainId = saleOrderMain.getId();
        List<VSaleOrderDetail> orderDetailList = saleOrderMain.getOrderDetailList();
        if(null == orderDetailList)throw new NuoNiuException("单据明细不能为空");
        UserInfo userInfo = UserThreadLocal.get();
        VSaleOrderMain oldVSaleOrderMain =null;
        if(mainId != null) {

            //校验详情（详情不能有其他单据的明细ID）
            boolean isHaveErrorId = orderDetailList.stream().anyMatch(f -> null != f.getOrderId() && !mainId.toString().equals(f.getOrderId().toString()));
            if(isHaveErrorId)throw new NuoNiuException("单据明细错误：不能修改其他单据的明细记录");
            oldVSaleOrderMain = getById(mainId);
            Integer voucherState = oldVSaleOrderMain.getVoucherState();
            /**************  修改权限 *******************/
            if(!crmGoodsService.isHaveOperationRight(oldVSaleOrderMain.getCreateUserId().longValue())){
                throw new NuoNiuException("你没有权限操作该记录");
            }
            if(null != voucherState && voucherState > 0){
                throw new NuoNiuException("已审核,不能修改");
            }
            saleOrderMain.setUpdateUserId(userInfo.getUserId());
            saleOrderMain.setUpdateUserName(userInfo.getRealName());
            saleOrderMain.setAccountId(oldVSaleOrderMain.getAccountId());
            saleOrderMain.setSourceVoucherCode(oldVSaleOrderMain.getSourceVoucherCode());
            saleOrderMain.setSourceVoucherId(oldVSaleOrderMain.getSourceVoucherId());
            saleOrderMain.setSourceVoucherType(oldVSaleOrderMain.getSourceVoucherType());
            saleOrderMain.setSourceVoucherDate(oldVSaleOrderMain.getSourceVoucherDate());
            //不可更新字段
            saleOrderMain.setVoucherCode(null);
            saleOrderMain.setCumExecuteQuantity(null);
        }else {
            String dataSource = saleOrderMain.getDataSource();
            if(StringUtils.isBlank(dataSource))throw new NuoNiuException("参数错误：数据来源");
            isNewMain = true;
            String code = getCode(userInfo.getCompanyId(), dataSource);
            if(StringUtils.isBlank(code)) {
                throw new NuoNiuException("单据编码今日已上限");
            }
            //校验详情（详情不能有ID）
            boolean isHaveId = orderDetailList.stream().anyMatch(f -> null != f.getId());
            if(isHaveId)throw new NuoNiuException("单据明细错误：不能新增已经存在的明细记录");
            saleOrderMain.setCompanyId(userInfo.getCompanyId());
            saleOrderMain.setVoucherState(-1);
            saleOrderMain.setVoucherCode(code);
            saleOrderMain.setAccountId(accountService.getCurrentAccountId());
            saleOrderMain.setCreateUserId(userInfo.getUserId());
            saleOrderMain.setCreateUserName(userInfo.getRealName());
            saleOrderMain.setCumExecuteQuantity(new BigDecimal(0.0));
        }

        if(StringUtils.isNotBlank(saleOrderMain.getProjectName())) { //西亚/项目新增
            ErpProject project = projectService.getByName(saleOrderMain.getProjectName());
            if(project == null) {
                project = new ErpProject();
                project.setName(saleOrderMain.getProjectName());
                projectService.saveErpProject(project);
            }
            saleOrderMain.setProjectId(project.getId().intValue());
        }

        //校验 客户档案
        Integer crmId = saleOrderMain.getCrmId();
        crmCustomerService.checkForFinance(crmId);
        // 校验 明细数量
        boolean isOk = saleOrderMain.getOrderDetailList().stream().anyMatch(f -> null == f.getBaseQuantity() || !(f.getBaseQuantity().compareTo(BigDecimal.ZERO) > 0));
        if(isOk)throw new NuoNiuException("明细数量必须大于0");
        //计算 明细物料 总数
        BigDecimal totalQuantity =  saleOrderMain.getOrderDetailList().stream().map(VSaleOrderDetail::getBaseQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
        saleOrderMain.setTotalQuantity(totalQuantity.abs());

        Boolean result = this.saveOrUpdate(saleOrderMain);
        if(result) {
            List<Long> detailIds = new ArrayList<>();
            orderDetailList.forEach(p -> {
                p.setOrderId(saleOrderMain.getId().intValue());
                p.setCompanyId(userInfo.getCompanyId());
                p.setAccountId(saleOrderMain.getAccountId());
                p.setSourceVoucherType(saleOrderMain.getSourceVoucherType());
                p.setSourceVoucherCode(saleOrderMain.getSourceVoucherCode());
                p.setSourceVoucherId(saleOrderMain.getSourceVoucherId());
                p.setSourceVoucherDate(saleOrderMain.getSourceVoucherDate());
                if(p.getId() != null) {
                    detailIds.add(p.getId());
                }
            });

            boolean isDealDelete = false;
            if (null != mainId){
                //删除明细
                QueryWrapper wrapper = new QueryWrapper();
                wrapper.eq("order_id", mainId);
                if(detailIds != null && detailIds.size() > 0) {
                    wrapper.notIn("id", detailIds);
                }
                isDealDelete = orderDetailService.remove(wrapper);
            }
            //保存单据明细表
            orderDetailService.saveOrUpdateBatch(orderDetailList);
            // *** 如果 来源订单不为空,校验
            if(null != saleOrderMain.getSourceVoucherId() && !"Contract".equals(saleOrderMain.getSourceVoucherType())){
                if(isDealDelete)throw new NuoNiuException("有来源的单据不能删除明细");
                if(!"SaleQuotation".equals(saleOrderMain.getSourceVoucherType()) && !"Contract".equals(saleOrderMain.getSourceVoucherType()))throw new NuoNiuException("销售订单的来源单，只能是报价单");
                VoucherMainBo voucherMainBo = new VoucherMainBo();
                BeanUtils.copyProperties(saleOrderMain,voucherMainBo);
                voucherMainBo.setIsNewMain(isNewMain);
                List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
                orderDetailList.forEach(detail->{
                    VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                    voucherDetailBos.add(voucherDetailBo);
                    BeanUtils.copyProperties(detail,voucherDetailBo);
                });
                VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
                voucherSearchBo.setSourceVoucherId(saleOrderMain.getSourceVoucherId());
                voucherSearchBo.setSourceVoucherType(saleOrderMain.getSourceVoucherType());
                voucherSearchBo.setVoucherId(saleOrderMain.getId().intValue());
                voucherSearchBo.setVoucherType("SaleOrder");
                erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
            }
        }
    }

    @Override
    public void submit(Long id, Integer status) {
        if(null == id || null == status || (null != status && (status > 0 || status < -1 )))throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        VSaleOrderMain saleOrderMain = this.getById(id);
        if( null == saleOrderMain)throw new NuoNiuException("记录不存在");
        //校验状态
        Integer voucherState = saleOrderMain.getVoucherState();
        /**  统一校验 提交状态 */
        ErpUtils.checkSubmitStatus(voucherState,status);
        //提交
        saleOrderMain.setVoucherState(status);
        saleOrderMain.setSubmitDate(LocalDateTime.now());
        saleOrderMain.setSubmitUserId(userInfo.getUserId());
        saleOrderMain.setSubmitUserName(userInfo.getRealName());
        this.updateById(saleOrderMain);
    }

    @Override
    public void examine(Long id, Integer status) {
        if(null == id || null == status ||  (status > 1 || status < 0) )throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        VSaleOrderMain saleOrderMain = getById(id);

        if(saleOrderMain == null) {
            throw new NuoNiuException("单据不存在");
        }

        if(saleOrderMain.getVoucherState().equals(10)) {
            throw new NuoNiuException("单据已关闭");
        }

        Integer voucherState = saleOrderMain.getVoucherState();
        BigDecimal cumExecuteQuantity = saleOrderMain.getCumExecuteQuantity();
        /** 统一校验 审核状态*/
        ErpUtils.checkExamineStatus(voucherState,status,cumExecuteQuantity);
        saleOrderMain.setVoucherState(status);
        saleOrderMain.setReviewerDate(LocalDateTime.now());
        saleOrderMain.setReviewerUserId(userInfo.getUserId());
        saleOrderMain.setReviewerUserName(userInfo.getRealName());
        updateById(saleOrderMain);
    }

    @Override
    public Page<VSaleOrderMain> pageList(Page pages, VSaleOrderMain saleOrderMain) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = accountService.getCurrentAccountId();
        QueryWrapper<VSaleOrderMain> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id", userInfo.getCompanyId());
        queryWrapper.eq("account_id", currentAccountId);
        return  page(pages, queryWrapper);
    }

    @Override
    public String getCode(Integer companyId, String dataSource) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = erpAccountService.getCurrentAccountId();
        ErpNumberSet numberSet = numberSetMapper.getByCode(dataSource, userInfo.getCompanyId(), currentAccountId);
        String dateStr = numberSet.getMedian() == 1 ? "%Y-%m-%d" : "%Y-%m";
        String code = baseMapper.getCode(userInfo.getCompanyId(), dateStr,dataSource);
        return numberSetService.getCode(numberSet, code);
    }

    @Override
    public List<VSaleOrderMain> getBySourceId(Long sourceId) {
        return baseMapper.getBySourceId(sourceId);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteById(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        VSaleOrderMain saleOrderMain = getById(id);
        if(saleOrderMain == null) {
            throw new NuoNiuException("单据已删除");
        }
        /**************  修改权限 *******************/
        if(!crmGoodsService.isHaveOperationRight(saleOrderMain.getCreateUserId().longValue())){
            throw new NuoNiuException("你没有权限操作该记录");
        }
        if(saleOrderMain.getIsGenerateWorkPlan())throw new NuoNiuException("已经生成主生产计划，不能删除");
        BigDecimal cumExecuteQuantity = saleOrderMain.getCumExecuteQuantity();
        if(null != cumExecuteQuantity && cumExecuteQuantity.compareTo(BigDecimal.ZERO) > 0){
            throw new NuoNiuException("单据已生成销售发货单据，不能删除");
        }
        List<VSaleOrderDetail> orderDetails = orderDetailService.getDetailsByOrderId(id);
        // *** 如果 来源订单不为空,校验
        if(null != saleOrderMain.getSourceVoucherId()){
            VoucherMainBo voucherMainBo = new VoucherMainBo();
            BeanUtils.copyProperties(saleOrderMain,voucherMainBo);
            List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
            orderDetails.forEach(detail->{
                VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                voucherDetailBos.add(voucherDetailBo);
                BeanUtils.copyProperties(detail,voucherDetailBo);
            });
            VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
            voucherSearchBo.setCalculateType(2);
            voucherSearchBo.setSourceVoucherId(saleOrderMain.getSourceVoucherId());
            voucherSearchBo.setSourceVoucherType(saleOrderMain.getSourceVoucherType());
            voucherSearchBo.setVoucherId(saleOrderMain.getId().intValue());
            voucherSearchBo.setVoucherType("SaleOrder");
            erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
        }
        removeById(id);
        orderDetailService.removeByOrderId(id);
    }

    @Override
    public Map getOrderList() {
        QueryWrapper wrapper = new QueryWrapper();
        Map<String, Object> data = new HashMap<>();
        UserInfo userInfo = UserThreadLocal.get();
        wrapper.eq("company_id", userInfo.getCompanyId());
        wrapper.eq("account_id", accountService.getCurrentAccountId());
        wrapper.eq("is_operation", 0);
        wrapper.eq("voucher_state", 1);
        wrapper.orderByDesc("id");
        List<VSaleOrderMain> saleOrderMains = this.list(wrapper);
        List<VSaleOrderDetail> saleOrderDetails = orderDetailService.getList(userInfo.getCompanyId());
        data.put("saleOrderMain", saleOrderMains);
        data.put("saleOrderDetail", saleOrderDetails);
        return data;
    }

    @Override
    @Async
    public void updateOperationStatus(List<ErpMrpRecord> mrpData) {
        mrpData.forEach(m -> {
            if(m.getVoucherType().equals(1)) {
                orderDetailService.updateOperationStatus(m.getVoucherId());
                Integer count = orderDetailService.getOperationCount(m.getOrderId());
                if(count == 0) {
                    VSaleOrderMain saleOrderMain = new VSaleOrderMain();
                    saleOrderMain.setId(m.getOrderId().longValue());
                    saleOrderMain.setIsOperation(true);
                    updateById(saleOrderMain);
                }
            } else if(m.getVoucherType().equals(2)) {
                
            } else {
                productionPlanDetailService.updateOperationStatus(m.getVoucherId());
                Integer count = productionPlanDetailService.getOperationCount(m.getOrderId());
                if(count == 0) {
                    VProductionPlanMain productionPlanMain = new VProductionPlanMain();
                    //productionPlanMain.setIsOperation(true);
                    productionPlanMain.setId(m.getOrderId().longValue());
                    productionPlanMainService.updateById(productionPlanMain);
                }
            }

        });
    }

    @Override
    public boolean updateGenerateWorkPlanStatus(Long saleOrderId, Integer status) {
        boolean b = baseMapper.updateGenerateWorkPlanStatus(saleOrderId, status);
        return b;
    }

    @Override
    public void closed(Long id, Integer status) {
        if(status == null || id == null) {
            throw new NuoNiuException("参数错误！！！");
        }

        UserInfo userInfo = UserThreadLocal.get();
        VSaleOrderMain saleOrderMain = this.getById(id);
        if(status.equals(1)) {
            if(saleOrderMain.getReleaseState().equals(2)) {
                throw new NuoNiuException("已生单不能打开");
            }
        } else {
            if(!saleOrderMain.getVoucherState().equals(1)) {
                throw new NuoNiuException("已审核状态的订单才能关闭");
            }
        }

        saleOrderMain.setVoucherState(status);
        saleOrderMain.setClosedDate(LocalDate.now());
        saleOrderMain.setCloserId(userInfo.getUserId());
        saleOrderMain.setCloserName(userInfo.getUserName());
        saleOrderMain.setId(id);
        updateById(saleOrderMain);
    }

}
